package org.gwtEss.table;

import java.util.ArrayList;
import java.util.List;

import org.gwtEss.menu.Menu;
import org.gwtEss.menu.MenuItem;
import org.gwtEss.menu.MenuItemBase;
import org.gwtEss.menu.MenuItemSeperator;
import org.gwtEss.menu.MenuItemTitle;
import org.gwtEss.menu.SubMenuItems;
import org.gwtEss.other.HasDragEvents;
import org.gwtEss.other.HasWidgetResizerRequiredHandlers;
import org.gwtEss.other.WidgetResizer;
import org.gwtEss.table.HeaderTable.HasTextArea;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasMouseDownHandlers;
import com.google.gwt.event.dom.client.HasMouseMoveHandlers;
import com.google.gwt.event.dom.client.HasMouseOutHandlers;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DeckPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;

public abstract class HeaderWidget<VO> extends  Composite implements HasDragEvents, HasWidgetResizerRequiredHandlers, HasMouseOutHandlers, HasColWidgetFunctions<VO>{

	short MIN_WIDTH = 20; 
	private FlexTable flexTable; 
	private SimplePanel mainPanel;
	private DeckPanel sortIndicator;
	private Widget filterIndicator;
	private Widget menuWidget;
	private Widget textWidget;
//	private SimplePanel textArea;
	private Menu headerMenu; //TODO: Use a shared header menu. New menu for each column is waste of resources.
//	private int pxWidth; 
	private boolean menuShowing = false;
	private Cols<VO> cols; 
	private ColWidget<VO> colWidget;
	public HeaderWidget(Cols<VO> cols, ColWidget<VO> colWidget, int width) {
		this.cols = cols;
		this.colWidget = colWidget;
		flexTable = new FlexTable();
//		flexTable.setBorderWidth(1);
		flexTable.setCellPadding(0);
		flexTable.setCellSpacing(0);
//		textArea = new SimplePanel();
//		textArea.addStyleName("divClip");
		textWidget = (Widget)createTextWidget(colWidget.getColName());
//		((HasTextArea)textWidget).setText(text);
		textWidget.setWidth(width + "px");
		assert (textWidget instanceof HasTextArea):"textWidget should be instance of HasTextArea";
//		textArea.setWidget((Widget)textWidget);
		HasMouseMoveHandlers menuW = createMenuWidget();
		assert (menuW instanceof Widget):"menuWidget should be instance of Widget";
		menuWidget = (Widget)menuW;
		int colNum = 0; 
		textWidget.addStyleName("divClip");
//		resize();
		flexTable.setWidget(0, colNum++, textWidget);
		flexTable.setWidget(0, colNum++, sortIndicator = createSortIndicator());
		flexTable.setWidget(0, colNum++, filterIndicator = createFilterIndicator());
		flexTable.setWidget(0, colNum++, menuWidget);
		sortIndicator.setVisible(false);
		filterIndicator.setVisible(false);
		((Widget)menuWidget).setVisible(false);
		new WidgetResizer((Widget)this){
			private void setPixelSize() {
				// TODO Auto-generated method stub

			}
			@Override
			public void onDragStart(int mouseX, int mouseY) {
				super.onDragStart(mouseX, mouseY);
				HeaderWidget.this.onDragStart(mouseX, mouseY);
			}
			@Override
			public void onDrag(int mouseX, int mouseY, int deltaX,
					int deltaY) {
				super.onDrag(mouseX, mouseY, deltaX, deltaY);
				HeaderWidget.this.onDrag(mouseX, mouseY, deltaX, deltaY);
			}
			@Override
			public void onDragEnd(int mouseX, int mouseY, int deltaX,
					int deltaY) {
				super.onDragEnd(mouseX, mouseY, deltaX, deltaY);
				HeaderWidget.this.onDragEnd(mouseX, mouseY, deltaX, deltaY);
			}
		};
//		initWidget(mainPanel = new SimplePanel(){
//			{
//				addStyleName("detail11111");
//				setWidth("100%");
//				setWidget(flexTable);
//			}
//		});
//		flexTable.setWidth("100%");
		initWidget(flexTable);
		addMouseMoveHandler(new MouseMoveHandler() {
			
			@Override
			public void onMouseMove(MouseMoveEvent event) {
				HeaderWidget.this.onMouseMove();
			}
		});
		addMouseOutHandler(new MouseOutHandler() {
			
			@Override
			public void onMouseOut(MouseOutEvent event) {
				HeaderWidget.this.onMouseOut();
			}
		});
		
		((HasMouseDownHandlers)menuWidget).addMouseDownHandler(new MouseDownHandler() {
			
			@Override
			public void onMouseDown(MouseDownEvent event) {
				showHeaderMenu();
			}

		});
//		menuButton.addAutoHidePartner(menuWidget.getElement());
//		resize();
	}
	private void showHeaderMenu() {
		if (headerMenu == null){
			headerMenu = new Menu() {
				
				@Override
				public int getMenuTop() {
					return menuWidget.getAbsoluteTop() + menuWidget.getOffsetHeight();
				}
				
				@Override
				public int getMenuLeft() {
					return menuWidget.getAbsoluteLeft();
				}
			};
			headerMenu.addCloseHandler(new CloseHandler<PopupPanel>() {
				
				@Override
				public void onClose(CloseEvent<PopupPanel> event) {
					onMouseOut();
				}
			});	
			headerMenu.addAutoHidePartner(HeaderWidget.this.getElement());
			headerMenu.setData(createMenuData());
		}
		headerMenu.show();
	}
	private List<? extends MenuItemBase> createMenuData() {
		return new ArrayList<MenuItemBase>(){
			{
				add(new MenuItemTitle("Sort"));
				add(new MenuItem("Sort Ascending") {
					
					@Override
					public boolean onSelect() {
						onSortAsc();
//						setSortIndicatorState();
						return true;
					}
					{
						setIcon(new Image("images/mini/arrow_down.gif"));
					}
				});
				add(new MenuItem("Sort Descending") {
					
					@Override
					public boolean onSelect() {
						onSortDsc();
//						setSortIndicatorState();
						return true;
					}
					{
						setIcon(new Image("images/mini/arrow_up.gif"));
					}
				});
				add(new MenuItemSeperator());
				add(new MenuItem("Hide Columns") {
					{
						setSubMenu(new SubMenuItems(){
							{
								int colsSize = cols.size();
								add(new MenuItemTitle("Columns"));
								
								for (int i=0; i< colsSize; i++){
									final ColWidget col = cols.get(i);
									add(new MenuItem(col.getColName()) {
										private CheckBox chk = new CheckBox();
										@Override
										public boolean onSelect() {
											boolean val = !chk.getValue();
											System.out.println("val: " + val);
											chk.setValue(val);
											col.setVisible(val);
											onColVisibilityChanged(cols);
											return false;
										}
										
										{
											chk.addClickHandler(new ClickHandler() {//checkbox click event conflicts with menu item select event. that is why this stupid fix. 
												
												@Override
												public void onClick(ClickEvent event) {
													chk.setValue(!chk.getValue());	
												}
											});
											chk.setValue(col.isVisible());
											setIcon(chk);
										}
									});
								}
								
							}
						});
					}
					@Override
					public boolean onSelect() {
						return false;
					}
				});
				
			}
		};
	}
	@Override
	protected void onAttach() {
		super.onAttach();
//		pxWidth = getOffsetWidth();
	}
	private boolean hilited = false; 
	void onMouseMove() {
		if (hilited) return;
		int availableWidth = getContainerWidth();
//		setSortIndicatorState();
		filterIndicator.setVisible(isFiltered());
		menuWidget.setVisible(true);
		
		setPixelWidth(availableWidth);
		
//		int width = availableWidth 
//		- (sortIndicator.getOffsetWidth())
//		- (filterIndicator.getOffsetWidth())
//		- (menuWidget.getOffsetWidth());
////		if (width > MIN_WIDTH)
//			textWidget.setWidth(width + "px");
		addStyleName("tableHeaderCellBorder-hilite");
		hilited = true; 
//		System.out.println("setting width: " + width + ", availablewidth: " + availableWidth);
//		resize();
	}
	
	void setSortIndicatorState() {//some error here! 
		Boolean isAsc = colWidget.getSortAsc();  
		sortIndicator.setVisible(isAsc != null);
		if (isAsc != null)
			sortIndicator.showWidget(isAsc?0:1);
			
	}
	private boolean isFiltered() {
		return false;
	}
	void onMouseOut() {
		if (headerMenu!=null && headerMenu.isShowing()) return;
		int availableWidth = getContainerWidth();
		removeStyleName("tableHeaderCellBorder-hilite");
		hilited = false;
//		if (width > MIN_WIDTH)
//			textWidget.setWidth(width + "px");
		
//		sortIndicator.setVisible(false);
		filterIndicator.setVisible(false);
		menuWidget.setVisible(false);
		
//		System.out.println("setting available width: " + width);
		
		setPixelWidth(availableWidth);
		

//		resize();
	}
	@Override
	public void setSize(String width, String height) {
		super.setSize(width, height);
		resize();
	}
	@Override
	public void setPixelSize(int width, int height) {
//		super.setPixelSize(width, height);
//		resize();
		setPixelWidth(width);
		setPixelHeight(height);
	}
	private void setPixelHeight(int height) {
		super.setHeight(height+"px");
	}
//	@Override
//	public void setWidth(String width) {
//		assert false: "set the width of containing cell, then use resize()";
//	}
	@Override
	public void setWidth(String width) {
		super.setWidth(width);
		
	}
	void clearSortIndicator() {
		colWidget.setSortAsc(null);
		sortIndicator.setVisible(false);
	}
//	@Override
//	public void setPixelSize(int width, int height) {
//		setPixelWidth(width);
////		super.setPixelSize(width, height);
//	}
//	public void setPixelWidth(int pxWidth) {
//		this.pxWidth = pxWidth;
//		resize();
//	}
	boolean setPixelWidth(int width) {
		System.out.println("--width = " + width);
		int w = width 
		- (sortIndicator.isVisible()?sortIndicator.getOffsetWidth():0)
		- (filterIndicator.isVisible()?filterIndicator.getOffsetWidth():0)
		- (menuWidget.isVisible()?menuWidget.getOffsetWidth():0);
		if (w > MIN_WIDTH){
			textWidget.setWidth(w + "px");
			flexTable.setWidth(width + "px");
			return true; 
		}
		return false; 
	}
	public void resize(){
		System.out.println("resize called");
		setPixelWidth(getContainerWidth());
		setHeight(getContainerHeight() + "px");
	}
	
	public void setText(String text) {
		((HasTextArea)textWidget).setText(text);
	}
	private Widget createFilterIndicator() {
		return new Label("F");
	}
	private HasMouseMoveHandlers createMenuWidget() {
//		Label menu = new Label("V");
		HTML menu = new HTML("<img src='images/mint/arrow_down_grey.png'/>");
		return menu;
	}
	private DeckPanel createSortIndicator() {
		DeckPanel dp = new DeckPanel();
		dp.add(new HTML("<img src='images/mini/arrow_down.gif'/>"));
		dp.add(new HTML("<img src='images/mini/arrow_up.gif'/>"));
		return dp;
	}
	HasTextArea createTextWidget(String text) {
		return new DefaultColHeaderTextWidget(text);
	}
	@Override
	public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
		return addDomHandler(handler, MouseMoveEvent.getType());
	}

	@Override
	public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) {
		return addDomHandler(handler, MouseDownEvent.getType());
	}
	@Override
	public HandlerRegistration addMouseOutHandler(MouseOutHandler handler) {
		return addDomHandler(handler, MouseOutEvent.getType());
	}
	@Override
	public void onDrag(int mouseX, int mouseY, int deltaX, int deltaY) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void onDragEnd(int mouseX, int mouseY, int deltaX, int deltaY) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void onDragStart(int mouseX, int mouseY) {
		// TODO Auto-generated method stub
		
	}
	class DefaultColHeaderTextWidget extends HTML implements HasTextArea{

		public DefaultColHeaderTextWidget(String text) {
			setText(text);
		}
		@Override
		public void setText(String text) {
			setHTML(text);
		}
		
	}

}
